﻿using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using JetBrains.Application.Progress;
using JetBrains.DocumentModel;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Feature.Services.Bulbs;
using JetBrains.ReSharper.Feature.Services.CSharp.Bulbs;
using JetBrains.ReSharper.Feature.Services.LiveTemplates.Hotspots;
using JetBrains.ReSharper.Feature.Services.LiveTemplates.LiveTemplates;
using JetBrains.ReSharper.Intentions.Util;
using JetBrains.ReSharper.LiveTemplates;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.Tree;
using JetBrains.ReSharper.Psi.Util;
using JetBrains.TextControl;
using JetBrains.Util;
using MugenMvvmToolkit.ReSharper.Infrastructure;

namespace MugenMvvmToolkit.ReSharper.ViewModels.ContextActions
{
    [ContextAction(Name = "ModelPropertyAttributeAction", Group = "C#", Priority = 1)]
    public class ModelPropertyAttributeAction : PropertyContextAction
    {
        #region Fields

        private IClass _modelClass;

        #endregion

        #region Constructors

        public ModelPropertyAttributeAction([NotNull] ICSharpContextActionDataProvider provider)
            : base(provider)
        {
        }

        #endregion

        #region Overrides of ContextActionBase

        /// <summary>
        ///     Popup menu item text
        /// </summary>
        public override string Text
        {
            get { return UiResources.AddModelPropertyAttribute; }
        }

        /// <summary>
        ///     Executes QuickFix or ContextAction. Returns post-execute method.
        /// </summary>
        /// <returns>
        ///     Action to execute after document and PSI transaction finish. Use to open TextControls, navigate caret, etc.
        /// </returns>
        protected override Action<ITextControl> ExecutePsiTransaction(ISolution solution, IProgressIndicator progress)
        {
            IAttribute attribute = AddModelPropertyAttribute(Provider.ElementFactory, TypeProvider, PropertyDeclaration);
            var expression = attribute.ConstructorArgumentExpressions.SingleOrDefault() as ICSharpLiteralExpression;
            if (expression == null)
                return null;
            return GetHotspotAction(LiveTemplatesManager, _modelClass, expression, solution);
        }

        /// <summary>
        ///     Check if this action is available at the constructed context.
        ///     Actions could store precalculated info in <paramref name="cache" /> to share it between different actions
        /// </summary>
        /// <returns>
        ///     true if this bulb action is available, false otherwise.
        /// </returns>
        protected override bool IsAvailableInternal(IUserDataHolder cache)
        {
            if (!TypeProvider.ModelPropertyAttribute.IsResolved)
                return false;
            IType entityModelType = ToolkitExtensions.GetEntityModelType(ClassDeclaration);
            if (entityModelType == null)
                return false;
            _modelClass = entityModelType.GetClassType();
            return ToolkitExtensions.GetModelProperties(_modelClass).Any();
        }

        #endregion

        #region Methods

        public static IAttribute AddModelPropertyAttribute(CSharpElementFactory factory, TypeProvider typeProvider,
            IPropertyDeclaration target, string defaultValue = "")
        {
            IAttribute attribute = factory
                .CreateAttribute(typeProvider.ModelPropertyAttribute.GetTypeElement(),
                    new[] { new AttributeValue(new ConstantValue(defaultValue, typeProvider.String, typeProvider.PsiModule)) },
                    new Pair<string, AttributeValue>[0]);
            attribute = target.AddAttributeAfter(attribute, null);
            ContextActionUtils.FormatWithDefaultProfile(
                (ITreeNode)(AttributeSectionNavigator.GetByAttribute(attribute) ?? (object)attribute));
            return attribute;
        }

        public static Action<ITextControl> GetHotspotAction(LiveTemplatesManager manager, IClass modelClass,
            ICSharpLiteralExpression expression, ISolution solution)
        {
            return control =>
            {
                List<string> names = ToolkitExtensions.GetModelProperties(modelClass)
                    .Select(property => property.ShortName)
                    .ToList();
                DocumentRange range = expression.Literal.GetDocumentRange();
                range = new DocumentRange(range.Document,
                    new TextRange(range.TextRange.StartOffset + 1, range.TextRange.EndOffset - 1));

                var field = new TemplateField("NAME", new TextHotspotExpression(names), 0);
                manager.TryExecuteHotspotDefault(solution, control, new HotspotInfo(field, range));
            };
        }

        #endregion
    }
}